home *** CD-ROM | disk | FTP | other *** search
/ SGI Hot Mix 17 / Hot Mix 17.iso / HM17_SGI / research / lib / cw_pdmenu.pro < prev    next >
Text File  |  1997-07-08  |  11KB  |  334 lines

  1. ; $Id: cw_pdmenu.pro,v 1.16 1997/01/29 22:44:21 lubos Exp $
  2. ;
  3. ; Copyright (c) 1992-1997, Research Systems, Inc.  All rights reserved.
  4. ;    Unauthorized reproduction prohibited.
  5. ;+
  6. ; NAME:
  7. ;    CW_PDMENU
  8. ;
  9. ; PURPOSE:
  10. ;    CW_PDMENU is a compound widget that simplifies creating
  11. ;    pulldown menus. It has a simpler interface than the XPDMENU
  12. ;    procedure, which it is intended to replace. Events for the
  13. ;    individual buttons are handled transparently, and a CW_PDMENU
  14. ;    event returned. This event can return any one of the following:
  15. ;               - The Index of the button within the base.
  16. ;               - The widget ID of the button.
  17. ;               - The name of the button.
  18. ;        - The fully qualified name of the button. This allows
  19. ;          different sub-menus to contain buttons with the same
  20. ;          name in an unambiguous way.
  21. ;
  22. ;
  23. ; CATEGORY:
  24. ;    Compound widgets.
  25. ;
  26. ; CALLING SEQUENCE:
  27. ;    widget = CW_PDMENU(Parent, Desc)
  28. ;
  29. ; INPUTS:
  30. ;       Parent:    The ID of the parent widget.
  31. ;    Desc:    An array of strings or structures.  Each element contains
  32. ;        a menu description with two fields, a flag field, and
  33. ;        the name of the item.  If a structure, each element
  34. ;        is defined as follows:
  35. ;            { CW_PDMENU_S, flags:0, name:'' }
  36. ;
  37. ;        The name tag gives the name of button. The flags
  38. ;        field is a two-bit bitmask that controls how the button is
  39. ;        interpreted:
  40. ;
  41. ;            Value       Meaning
  42. ;            -------------------------------------------
  43. ;             0     This button is neither the beginning
  44. ;               nor the end of a pulldown level.
  45. ;             1     This button is the root of a
  46. ;                          sub-pulldown menu. The sub-buttons
  47. ;               start with the next button.
  48. ;             2     This button is the last button at the
  49. ;               current pulldown level. The next button
  50. ;               belongs to the same level as the current
  51. ;               parent button.
  52. ;               If none or empty string is specified as a
  53. ;               the name, the button is not created, but
  54. ;               the next button belongs to the upward level.
  55. ;             3     This button is the root of a sub-pulldown
  56. ;               menu, but it is also the last entry of
  57. ;               the current level.
  58. ;
  59. ;    If Desc is a string, each element contains the flag field
  60. ;    followed by a backslash character, followed by the menu item's
  61. ;    contents.  See the example below.
  62. ;
  63. ;    EVENT PROCEDURES:  An event procedure may be specified for an
  64. ;    element and all its children, by including a third field
  65. ;    in Desc, if Desc is a string array.  Events for buttons without
  66. ;    an event procedure, are dispatched normally.
  67. ;    See the example below.
  68. ;
  69. ; KEYWORD PARAMETERS:
  70. ;    DELIMITER:        The character used to separate the parts of a
  71. ;              fully qualified name in returned events. The
  72. ;              default is to use the '.' character.
  73. ;    FONT:          The name of the font to be used for the button
  74. ;              titles. If this keyword is not specified, the
  75. ;              default font is used.
  76. ;    HELP:          If MBAR is specified and one of the buttons on the
  77. ;              menubar has the label "help" (case insensitive) then
  78. ;              that button is created with the /HELP keyword to
  79. ;              give it any special appearance it is supposed to
  80. ;              have on a menubar. For example, Motif expects
  81. ;              help buttons to be on the right.
  82. ;    IDS:          A named variable into which the button IDs will
  83. ;              be stored as a longword vector.
  84. ;    MBAR:          if constructing a menu-bar pulldown, set this
  85. ;              keyword.  In this case, the parent must be the 
  86. ;              widget id of the menu bar of a top-level base,
  87. ;              returned by WIDGET_BASE(..., MBAR=mbar).
  88. ;    RETURN_ID:      If present and non-zero, the VALUE field of returned
  89. ;              events will be the widget ID of the button.
  90. ;    RETURN_INDEX:      If present and non-zero, the VALUE field of returned
  91. ;              events will be the zero-based index of the button
  92. ;              within the base. THIS IS THE DEFAULT.
  93. ;    RETURN_NAME:      If present and non-zero, the VALUE field of returned
  94. ;              events will be the name of the selected button.
  95. ;    RETURN_FULL_NAME: If present and non-zero, the VALUE field of returned
  96. ;                     events will be the fully qualified name of the
  97. ;              selected button. This means that the names of all
  98. ;              the buttons from the topmost button of the pulldown
  99. ;              menu to the selected one are concatenated with the
  100. ;              delimiter specified by the DELIMITER keyword. For
  101. ;              example, if the top button was named COLORS, the
  102. ;              second level button was named BLUE, and the selected
  103. ;              button was named LIGHT, the returned value would be
  104. ;
  105. ;              COLORS.BLUE.LIGHT
  106. ;
  107. ;              This allows different submenus to have buttons with
  108. ;              the same name (e.g. COLORS.RED.LIGHT).
  109. ;    UVALUE:          The user value to be associated with the widget.
  110. ;    XOFFSET:      The X offset of the widget relative to its parent.
  111. ;    YOFFSET:      The Y offset of the widget relative to its parent.
  112. ;
  113. ; OUTPUTS:
  114. ;       The ID of the top level button is returned.
  115. ;
  116. ; SIDE EFFECTS:
  117. ;    This widget generates event structures with the following definition:
  118. ;
  119. ;        event = { ID:0L, TOP:0L, HANDLER:0L, VALUE:0 }
  120. ;
  121. ;    VALUE is either the INDEX, ID, NAME, or FULL_NAME of the button,
  122. ;    depending on how the widget was created.
  123. ;
  124. ; RESTRICTIONS:
  125. ;    Only buttons with textual names are handled by this widget.
  126. ;    Bitmaps are not understood.
  127. ;
  128. ; EXAMPLE:
  129. ;    The following is the description of a menu bar with two buttons,
  130. ;    "Colors" and "Quit". Colors is a pulldown containing the colors
  131. ;    "Red", "Green", Blue", "Cyan", and "Magenta". Blue is a sub-pulldown
  132. ;    containing "Light", "Medium", "Dark", "Navy", and "Royal":
  133. ;
  134. ;        ; Make sure CW_PDMENU_S is defined
  135. ;        junk = { CW_PDMENU_S, flags:0, name:'' }
  136. ;
  137. ;        ; The description
  138. ;        desc = [ { CW_PDMENU_S, 1, 'Colors' }, $
  139. ;                 { CW_PDMENU_S, 0, 'Red' }, $
  140. ;                 { CW_PDMENU_S, 0, 'Green' }, $
  141. ;                 { CW_PDMENU_S, 1, 'Blue\BLUE_EVENT_PROC' }, $
  142. ;                     { CW_PDMENU_S, 0, 'Light' }, $
  143. ;                     { CW_PDMENU_S, 0, 'Medium' }, $
  144. ;                     { CW_PDMENU_S, 0, 'Dark' }, $
  145. ;                     { CW_PDMENU_S, 0, 'Navy' }, $
  146. ;                     { CW_PDMENU_S, 2, 'Royal' }, $
  147. ;                   { CW_PDMENU_S, 0, 'Cyan' }, $
  148. ;                   { CW_PDMENU_S, 2, 'Magenta\MAGENTA_EVENT_PROC' }, $
  149. ;             { CW_PDMENU_S, 2, 'Quit' } ]
  150. ;
  151. ;    The same menu may be defined as a string by equating the Desc parameter
  152. ;    to the following string array:
  153. ;    
  154. ;    desc =[ '1\Colors' , $
  155. ;        '0\Red' , $
  156. ;        '0\Green' , $
  157. ;        '1\Blue\BLUE_EVENT_PROC' , $
  158. ;        '0\Light' , $
  159. ;        '0\Medium' , $
  160. ;        '0\Dark' , $
  161. ;        '0\Navy' , $
  162. ;        '2\Royal' , $
  163. ;        '0\Cyan' , $
  164. ;        '2\Magenta\MAGENTA_EVENT_PROC' , $
  165. ;        '2\Quit'  ]
  166. ;
  167. ;
  168. ;    The following small program can be used with the above description
  169. ;    to create the specified menu:
  170. ;
  171. ;
  172. ;        base = widget_base()
  173. ;        menu = cw_pdmenu(base, desc, /RETURN_FULL_NAME)
  174. ;        WIDGET_CONTROL, /REALIZE, base
  175. ;        repeat begin
  176. ;          ev = WIDGET_EVENT(base)
  177. ;          print, ev.value
  178. ;        end until ev.value eq 'Quit'
  179. ;        WIDGET_CONTROL, /DESTROY, base
  180. ;        end
  181. ;
  182. ;    Note that independent event procedures were specified for
  183. ;    the multiple Blue buttons (blue_event_proc), and the Magenta button 
  184. ;    (magenta_event_proc).
  185.  
  186. ; MODIFICATION HISTORY:
  187. ;    18 June 1992, AB
  188. ;    16 Jan 1995, DMS, Added MBAR keyword, event procedures,
  189. ;            and menu descriptor strings.
  190. ;    2 July 1995, AB, Added HELP keyword.
  191. ;    3 September 1996, LP, Added button-less end of current level
  192. ;-
  193.  
  194.  
  195. function CW_PDMENU_EVENT, ev
  196.  
  197.   WIDGET_CONTROL, ev.id, get_uvalue=uvalue
  198.  
  199.   return, { ID:ev.handler, TOP:ev.top, HANDLER:0L, value:uvalue }
  200.  
  201. end
  202.  
  203.  
  204.  
  205.  
  206.  
  207.  
  208.  
  209. pro CW_PDMENU_BUILD, parent, desc, cur, n, ev_type, full_qual_str, $
  210.     delim, ids, mbars, HELP_KW, FONT=font
  211. ; Recursive routine that builds the pulldown hierarchy described in DESC.
  212. ; Returns the ID of each button in ids.
  213.  
  214.   is_string = size(desc)
  215.   is_string = is_string[is_string[0]+1] eq 7
  216.   while (cur lt n) do begin
  217.     if is_string then begin
  218.         ; String version of DESC structure
  219.     a = str_sep(desc[cur], '\')
  220.     dflags = fix(strtrim(a[0],2))
  221.         ; End of the level, and no button
  222.         if dflags EQ 2 AND N_ELEMENTS(a) LT 2 then begin
  223.             ids[cur] = 0
  224.             cur = cur + 1
  225.             return
  226.         endif
  227.         dname = a[1]
  228.     endif else begin
  229.         ; Structure version of DESC structure
  230.         dflags = desc[cur].flags
  231.         dname = desc[cur].name
  232.         ; End of the level, and no button
  233.         if dflags EQ 2 AND dname EQ '' then begin
  234.             ids[cur] = 0
  235.             cur = cur + 1
  236.             return
  237.         endif
  238.         a = ['', str_sep(dname, '\')]
  239.         dname = a[1]
  240.     endelse
  241.  
  242.     if (strlen(full_qual_str) ne 0) then $
  243.       new_qstr = full_qual_str + delim + dname $
  244.     else new_qstr = dname
  245.     ;If parented to a menu bar, don't draw a frame.
  246.     if (dflags and 1) then menu=2-mbars else menu = 0
  247.     ;
  248.     ; Build string with approriate keywords and execute it
  249.     ;
  250.     strExecute = 'new = WIDGET_BUTTON(parent, value=dname, MENU=menu'
  251.     if ((mbars ne 0) and (HELP_KW ne 0) $
  252.         and (strupcase(dname) eq 'HELP')) then $
  253.       strExecute = strExecute + ', /HELP'
  254.     if (keyword_set(font)) then strExecute = strExecute + ',  FONT=font'
  255.     strExecute = strExecute + ')'
  256.  
  257.     status = EXECUTE(strExecute)
  258.  
  259.     ; Set requested Return value
  260.     case ev_type of
  261.       0: uvalue = cur
  262.       1: uvalue = new
  263.       2: uvalue = dname
  264.       3: uvalue = new_qstr
  265.     endcase
  266.     WIDGET_CONTROL, new, SET_UVALUE=uvalue
  267.  
  268.     ; Register event procedure
  269.     if n_elements(a) ge 3 then WIDGET_CONTROL, new, EVENT_PRO=strtrim(a[2],2)
  270.     ids[cur] = new
  271.     cur = cur + 1
  272.  
  273.     ; Pullright menu button, start new level
  274.     if (dflags and 1) then $
  275.       CW_PDMENU_BUILD,new,desc,cur,n,ev_type,$
  276.       new_qstr,delim,ids,mbars, 0,FONT=font
  277.  
  278.     ; End of the current level
  279.     if ((dflags and 2) ne 0) then return
  280.   endwhile
  281.  
  282. end
  283.  
  284.  
  285.  
  286.  
  287.  
  288.  
  289. function CW_PDMENU, parent, desc, COLUMN=column, DELIMITER=delim, FONT=font, $
  290.     IDS=ids, MBAR=mbar, HELP=HELP_KW, $
  291.     RETURN_ID=r_id, RETURN_INDEX=ignore, RETURN_NAME=r_name, $
  292.     RETURN_FULL_NAME=r_full_name, $
  293.     UVALUE=uvalue, XOFFSET=xoffset, YOFFSET=yoffset
  294.  
  295.  
  296.   IF (N_PARAMS() ne 2) THEN MESSAGE, 'Incorrect number of arguments'
  297.  
  298.   ON_ERROR, 2                        ;return to caller
  299.  
  300.   ; Set default values for the keywords
  301.   If KEYWORD_SET(column) then row = 0 else begin row = 1 & column = 0 & end
  302.   IF (N_ELEMENTS(delim) eq 0)    then delim = '.'
  303.   IF (N_ELEMENTS(uvalue) eq 0)    then uvalue = 0
  304.   IF (N_ELEMENTS(xoffset) eq 0)    then xoffset=0
  305.   IF (N_ELEMENTS(yoffset) eq 0)    then yoffset=0
  306.  
  307.   ; How to interpret ev_type:
  308.   ;    0 - Return index
  309.   ;    1 - Return ID
  310.   ;    2 - Return name
  311.   ;    3 - Return fully qualified name.
  312.   ev_type = 0
  313.   if (keyword_set(r_id))     then ev_type = 1
  314.   if (keyword_set(r_name))     then ev_type = 2
  315.   if (keyword_set(r_full_name))    then ev_type = 3
  316.  
  317.  
  318.   n = n_elements(desc)
  319.   ids = lonarr(n)
  320.   mbars = KEYWORD_SET(mbar)
  321.   help_kw = KEYWORD_SET(HELP_KW)
  322.   if mbars then BEGIN
  323.     base = parent
  324.     if (keyword_set(uvalue)) then WIDGET_CONTROL, base, SET_UVALUE=uvalue
  325.   ENDIF else BEGIN
  326.     base = widget_base(parent, COLUMN=column, $
  327.              ROW=row, UVALUE=uvalue, XOFFSET=xoffset, YOFFSET=yoffset)
  328.   ENDELSE
  329.   WIDGET_CONTROL, base, EVENT_FUNC='CW_PDMENU_EVENT' 
  330.  CW_PDMENU_BUILD, base, desc, 0, n, ev_type, '', delim, ids, mbars, help_kw, $
  331.     FONT=font
  332.   return, base
  333. END
  334.